
#include <openssl/objects.h>
#include "ECDSAKeyPairGenerator.h"

/** Internal function to generate an ECDSA key pair with the given
 * number of bits and name.
 * 
 * @param nbits Number of bits desired in the key the be created.
 * 
 * @param name Name of the keys created.
 * 
 * @return Zero on success, 1 on key mismatch, -1 on generation
 * error. */
int ECDSAKeyPairGenerator::generateKeyPair(int nbits, const char *name)
{
   int nid = -1;
   switch (nbits)
   {
      case 256: nid = NID_X9_62_prime256v1; break;
      case 384: nid = NID_secp384r1; break;
      case 521: nid = NID_secp521r1; break;
      default: break;
   }
   if (nid == -1)
   {
      errprint("%d bits is an unsupported key length for ECDSA", nbits);
      return -1;
   }
   EC_KEY *dkey = EC_KEY_new_by_curve_name(nid);
   if (!dkey) { SSLCheckError(); EC_KEY_free(dkey); return -1; }
   if (!(EC_KEY_generate_key(dkey))) { SSLCheckError(); EC_KEY_free(dkey); return -1; }
   pub = new ECDSAPublicKey(dkey, name);
   prv = new ECDSAPrivateKey(dkey, name);
   EC_KEY_free(dkey);
   return (checkAreKeyPair()) ? 0 : 1;
}

/** Generate an ECDSA key pair with the given number of bits and name.
 * 
 * @param nbits Number of bits desired in the key the be created.
 * 
 * @param name Name of the keys created. */
ECDSAKeyPairGenerator::ECDSAKeyPairGenerator(int nbits, const char *name)
{
   generateKeyPair(nbits, name);
}

/** Copy constructor from the other key pair generator.
 * 
 * @param o The other instance to copy from. */
ECDSAKeyPairGenerator::ECDSAKeyPairGenerator(const ECDSAKeyPairGenerator &o)
{
   pub = (o.pub) ? new ECDSAPublicKey(*(o.pub)) : NULL;
   prv = (o.prv) ? new ECDSAPrivateKey(*(o.prv)) : NULL;
}

/** Copy assignment operator from the other key pair generator.
 * 
 * @param o The other instance to copy from.
 * 
 * @return This newly copied key pair generator. */
ECDSAKeyPairGenerator &ECDSAKeyPairGenerator::operator=(const ECDSAKeyPairGenerator &o)
{
   pub = (o.pub) ? new ECDSAPublicKey(*(o.pub)) : NULL;
   prv = (o.prv) ? new ECDSAPrivateKey(*(o.prv)) : NULL;
   return *this;
}

/** Destructor of the generator. Keys should be popped via
 * popPrivateKey and popPublicKey or they will be destroyed with the
 * generator. */
ECDSAKeyPairGenerator::~ECDSAKeyPairGenerator()
{
   if (pub) delete pub;
   pub = NULL;
   if (prv) delete prv;
   prv = NULL;
}

/** Check to see if the internally stored keys make a valid matching
 * key pair.
 * 
 * @return 1 if the keys make a matching pair, zero if they do not, -1
 * on error. */
int ECDSAKeyPairGenerator::checkAreKeyPair()
{
   if (!prv)
   {
      errprint("ECDSA private key has been popped!");
      return -1;
   }
   if (!pub)
   {
      errprint("ECDSA public key has been popped!");
      return -1;
   }
   return checkAreKeyPair(pub, prv);
}

/** Check to see if these keys make a valid matching key pair.
 * 
 * @param ipub An ECDSAPublicKey to test.
 * 
 * @param iprv An ECDSAPrivateKey to test.
 * 
 * @return 1 if the keys make a matching pair, zero if they do not, -1
 * on error. */
int ECDSAKeyPairGenerator::checkAreKeyPair(ECDSAPublicKey *ipub, ECDSAPrivateKey *iprv)
{
   if (!iprv)
   {
      errprint("ECDSA private key has been popped!");
      return -1;
   }
   if (!ipub)
   {
      errprint("ECDSA public key has been popped!");
      return -1;
   }
   return iprv->compareKeyBelongs(ipub);
}

/** Get the public key, but do not remove it from the key pair
 * storage. If it is not removed, it will be deleted along with this
 * class.
 * 
 * @return A pointer to the internally stored ECDSAPublicKey of the
 * generated pair. */
ECDSAPublicKey *ECDSAKeyPairGenerator::getPublicKey()
{
   return pub;
}

/** Get the private key, but do not remove it from the key pair
 * storage. If it is not removed, it will be deleted along with this
 * class.
 * 
 * @return A pointer to the internally stored ECDSAPrivateKey of the
 * generated pair. */
ECDSAPrivateKey *ECDSAKeyPairGenerator::getPrivateKey()
{
   return prv;
}

/** Get the public key, but remove it from the key pair storage, so it
 * is not deleted and freed along with this class.
 * 
 * @return A pointer to the ECDSAPublicKey of the generated pair. By
 * calling this, the key is removed from this generator instance, and
 * the responsibility to delete the key now rests with the
 * caller. Subsequent calls will return NULL. */
ECDSAPublicKey *ECDSAKeyPairGenerator::popPublicKey()
{
   ECDSAPublicKey *pub_k = pub;
   pub = NULL;
   return pub_k;
}

/** Get the private key, but remove it from the key pair storage, so
 * it is not deleted and freed along with this class.
 * 
 * @return A pointer to the ECDSAPrivateKey of the generated pair. By
 * calling this, the key is removed from this generator instance, and
 * the responsibility to delete the key now rests with the
 * caller. Subsequent calls will return NULL. */
ECDSAPrivateKey *ECDSAKeyPairGenerator::popPrivateKey()
{
   ECDSAPrivateKey *prv_k = prv;
   prv = NULL;
   return prv_k;
}
